package com.ep.thirdPlatformProject.erp.helper;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ep.thirdPlatformProject.erp.config.ErpConfig;
import com.ep.thirdPlatformProject.erp.entity.*;
import com.ep.thirdPlatformProject.system.util.RSAUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.xxl.job.core.context.XxlJobHelper;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.zip.GZIPInputStream;

@Component
@Slf4j
@RequiredArgsConstructor
public class ErpCommonHelper {

    private final ErpConfig erpConfig;


    /**
     * 解析响应到res
     *
     * @param response 响应
     * @return {@link ErpCommonExecution}
     */
    public ErpCommonExecution parseResponseToRes(@NotNull String response) {
        String decompressStr = decompress(response);
        log.info("【Erp响应】解压后：{}", decompressStr);
        XxlJobHelper.log("【Erp响应】解压后：" + decompressStr);
        JSONObject erpResponseJson = JSON.parseObject(decompressStr);

        if (erpResponseJson.isEmpty()) {
            return null; // 如果解析结果为空，直接返回null
        }

        ErpCommonResponse erpResponse = erpResponseJson.toJavaObject(ErpCommonResponse.class);
        ErpPayload stdData = erpResponse.getPayload();

        return validateExecution(stdData);
    }


    /**
     * 建立有效载荷
     *
     * @param t 对象
     * @return {@link ErpPayload}
     */
    public <T> String buildPayload(T t, @NotNull String serviceName) {
        return this.buildPayload(t, serviceName, false);
    }

    /**
     * 建立有效载荷
     *
     * @param t           t
     * @param serviceName 服务名称
     * @param isJackson   是否使用Jackson作为编码参数方式
     * @return {@link String }
     */
    public <T> String buildPayload(T t, @NotNull String serviceName, Boolean isJackson) {
        try {
            String jsonString;
            String finalString;
            ObjectMapper objMapper = new ObjectMapper();


            if (Boolean.TRUE.equals(isJackson)) {
                jsonString = objMapper.writeValueAsString(t);
                log.info("当前使用的json化方式为jackson");
            } else {
                jsonString = JSON.toJSONString(t);
                log.info("当前使用的json化方式为JSON");
            }

            log.info("【Erp请求】参数明文 ：{}", jsonString);
            String paramString = RSAUtils.encryptRSA(jsonString);
            log.info("【Erp请求】参数密文 ：{}", paramString);

            erpConfig.getService().setName(serviceName);

            ErpPayload erpPayload = new ErpPayload();
            ErpData erpData = new ErpData();
            ErpParameter erpParameter = new ErpParameter();
            erpParameter.setL_str(paramString);

            erpData.setParameter(erpParameter);
            erpPayload.setStd_data(erpData);

            erpConfig.setPayload(erpPayload);

            if (Boolean.TRUE.equals(isJackson)) {
                // 无法处理代理属性中的值，cglib等等，只能采用复制完成
                ErpConfig config = new ErpConfig();
                BeanUtil.copyProperties(erpConfig, config);
                finalString = objMapper.writeValueAsString(config);
            } else {
                finalString = JSON.toJSONString(erpConfig);
            }

            log.info("【Erp请求】请求最终参数 ：{}", finalString);
            return finalString;
        } catch (Exception e) {
            throw new RuntimeException("编码参数出现意外了：" + e.getMessage(), e);
        }

    }

    /**
     * ERP返回结果解压
     *
     * @param str str
     * @return {@link String}
     */
    private String decompress(String str) {
        try {
            if (str == null || str.isEmpty()) {
                return str;
            }
            ByteArrayInputStream is = new ByteArrayInputStream(Base64.getMimeDecoder().decode(str.getBytes(StandardCharsets.UTF_8)));
            GZIPInputStream gis = new GZIPInputStream(is);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buffer = new byte[256];
            int n;
            while ((n = gis.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
            return out.toString(StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("【Erp请求】解压失败:{}", e.getMessage(), e);
            return str;
        }
    }

    /**
     * 验证执行
     *
     * @param stdData 标准数据
     * @return {@link ErpCommonExecution}
     * @throws ErpResponseException Erp反应异常
     */
    private ErpCommonExecution validateExecution(ErpPayload stdData) throws ErpResponseException {
        if (stdData.getStd_data() == null) {
            // 显式地处理可能的null情况
            throw new ErpResponseException("Payload data is null.");
        }
        ErpCommonExecution execution = stdData.getStd_data().getExecution();

        if (!execution.getCode().equals("0")) {
            // 抛出更具体的异常，而不是RuntimeException
            throw new ErpResponseException("【Erp请求】请求失败，错误码：" + execution.getCode() + "，错误信息：" + execution.getDescription());
        }

        return execution;
    }

    static class ErpResponseException extends RuntimeException {
        public ErpResponseException(String message) {
            super(message);
        }

        public ErpResponseException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}
